/*
 * @(#)AssociationTransformer.java
 * Date 2013-09-05
 * Version 1.0
 * Author Jim Horner
 * Copyright (c)2012
 */


package us.hornerscorners.lamppost.registry.transformer.model;

import javax.enterprise.context.ApplicationScoped;

import javax.inject.Inject;

import oasis.names.tc.ebxml_regrep.xsd.rim._3.AssociationType1;
import oasis.names.tc.ebxml_regrep.xsd.rim._3.ClassificationType;
import oasis.names.tc.ebxml_regrep.xsd.rim._3.SlotType1;
import oasis.names.tc.ebxml_regrep.xsd.rim._3.ValueListType;

import org.apache.commons.lang3.StringUtils;

import us.hornerscorners.lamppost.exception.ConversionException;
import us.hornerscorners.lamppost.exception.ServiceActionError;
import us.hornerscorners.lamppost.exception.SeverityType;
import us.hornerscorners.lamppost.exception.ValidationException;

import us.hornerscorners.lamppost.model.common.IClassifiableModel;

import us.hornerscorners.lamppost.model.document.Association;
import us.hornerscorners.lamppost.model.document.Attribute;
import us.hornerscorners.lamppost.model.document.DocumentEntry;
import us.hornerscorners.lamppost.model.document.Folder;
import us.hornerscorners.lamppost.model.document.IAssociable;

import us.hornerscorners.lamppost.registry.constant.AssociationType;
import us.hornerscorners.lamppost.registry.constant.ErrorCode;
import us.hornerscorners.lamppost.registry.constant.Metadata;

import us.hornerscorners.lamppost.registry.utils.XDSUtils;

import us.hornerscorners.lamppost.transformer.AbstractTransformer;


/**
 * Class description
 *
 *
 * @version        v1.0, 2013-09-05
 * @author         Jim Horner
 */
@ApplicationScoped
public class AssociationTransformer
        extends AbstractTransformer<AssociationType1, Association> {

    /** Field description */
    @Inject
    private CodedElementTransformer codedElementTransformer;

    /**
     * Constructs ...
     *
     */
    public AssociationTransformer() {

        super();
    }

    /**
     * Method description
     *
     *
     * @param atype
     *
     * @return
     */
    @Override
    public Association transform(AssociationType1 atype) throws ValidationException {

        Association result = new Association();

        result.setEntryURN(XDSUtils.assignEntryUUID(atype.getId()));
        result.setAssociationType(atype.getAssociationType());

        // versioning
        result.setEntryLogicalURN(StringUtils.defaultIfBlank(atype.getLid(),
                result.getEntryURN()));
        result.setEntryVersion(
            StringUtils.defaultIfBlank(
                XDSUtils.parseVersionName(atype.getVersionInfo()), "1"));

        for (SlotType1 slot : atype.getSlot()) {

            Attribute attribute = new Attribute();

            attribute.setName(slot.getName());

            ValueListType values = slot.getValueList();

            if (values != null) {

                attribute.getValues().addAll(values.getValue());
            }

            result.getAttributes().add(attribute);
        }

        String docScheme = Metadata.AssociationClassificationNode.getURN();

        for (ClassificationType ctype : atype.getClassification()) {

            if (docScheme.equals(ctype.getClassificationScheme())) {

                result.setDocumentation(this.codedElementTransformer.transform(ctype));

                break;
            }
        }

        return result;
    }

    /**
     * Method description
     *
     *
     * @param atype
     * @param source
     * @param target
     *
     * @return
     */
    public Association transformAssociation(AssociationType1 atype, IAssociable source,
            IAssociable target, boolean sourceByRef, boolean targetByRef)
            throws ValidationException {

        Association result = transformSubmittedAssociation(atype, source, target,
                                 sourceByRef, targetByRef);

        result.setTargetUniqueId(target.getUniqueId());
        result.setTargetModelType(target.getModelType());

        return result;
    }

    /**
     * Method description
     *
     *
     * @param parentDoc
     * @param sourceByRef
     * @param targetByRef
     *
     * @return
     */
    public Association transformAssociation(DocumentEntry parentDoc, Folder source,
            DocumentEntry target, boolean sourceByRef, boolean targetByRef)
            throws ConversionException {

        Association result = null;

        Association currAssoc = null;
        String sourceURN = source.getEntryURN();

        for (Association assoc : parentDoc.getFolders()) {

            if (assoc.getSourceEntryURN().equals(sourceURN)) {

                currAssoc = assoc;

                break;
            }
        }

        if (currAssoc == null) {

            String msg =
                String.format("Folder [%s] does not contain parent document [%s].",
                              source.getEntryURN(), parentDoc.getEntryURN());
            ServiceActionError error =
                new ServiceActionError(ErrorCode.XDSRegistryMetadataError.getCode(), msg,
                                       SeverityType.Error);

            throw new ConversionException(getErrorLocation(), error);
        }

        result = new Association();
        result.setAssociationType(AssociationType.HasMember.getCode());
        result.setSourceByReference(sourceByRef);
        result.setSourceEntryURN(sourceURN);
        result.setSourceModelType(source.getModelType());
        result.setSourceUniqueId(source.getUniqueId());
        result.setTargetByReference(targetByRef);
        result.setTargetEntryURN(target.getEntryURN());
        result.setTargetModelType(target.getModelType());
        result.setTargetUniqueId(target.getUniqueId());

        result.setDocumentation(currAssoc.getDocumentation());
        result.getDescriptions().addAll(currAssoc.getDescriptions());
        result.getAttributes().addAll(currAssoc.getAttributes());
        result.getDisplayNames().addAll(currAssoc.getDisplayNames());

        return result;
    }

    /**
     * Method description
     *
     *
     * @param atype
     * @param source
     *
     * @return
     */
    public Association transformSubmittedAssociation(AssociationType1 atype,
            IAssociable source, IClassifiableModel target, boolean sourceByRef,
            boolean targetByRef)
            throws ValidationException {

        Association result = transform(atype);

        result.setSourceEntryURN(source.getEntryURN());
        result.setSourceUniqueId(source.getUniqueId());
        result.setSourceModelType(source.getModelType());
        result.setSourceByReference(sourceByRef);
        result.setTargetEntryURN(target.getEntryURN());
        result.setTargetByReference(targetByRef);

        return result;
    }
}
